{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2.0.0\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "print(tf.__version__)\n",
    "# from Ipython import display\n",
    "from matplotlib import pyplot as plt\n",
    "import random\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.1 gen_dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(<tf.Tensor: id=31, shape=(2,), dtype=float32, numpy=array([-0.26987994,  1.4564307 ], dtype=float32)>,\n",
       " <tf.Tensor: id=35, shape=(), dtype=float32, numpy=-1.3016337>)"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "num_inputs = 2\n",
    "num_examples = 1000\n",
    "true_w = [2, -3.4]\n",
    "true_b = 4.2\n",
    "features = tf.random.normal((num_examples, num_inputs),stddev = 1)\n",
    "labels = true_w[0] * features[:,0] + true_w[1] * features[:,1] + true_b\n",
    "labels += tf.random.normal(labels.shape,stddev=0.01)\n",
    "\n",
    "features[0], labels[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x1c2288c7808>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 252x180 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "def use_svg_display():\n",
    "    display.set_matplotlib_formats('svg')\n",
    "def set_figsize(figsize=(3.5, 2.5)):\n",
    "#     use_svg_display()\n",
    "    plt.rcParams['figure.figsize'] = figsize\n",
    "\n",
    "set_figsize()\n",
    "plt.scatter(features[:, 1], labels, 1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.2 read data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "def data_iter(batch_size, features, labels):\n",
    "    features = np.array(features)\n",
    "    labels = np.array(labels)\n",
    "    num_examples = len(features)\n",
    "    indices = list(range(num_examples))\n",
    "    random.shuffle(indices)\n",
    "    for i in range(0, num_examples, batch_size):\n",
    "        j = np.array(indices[i:min(i + batch_size, num_examples)])\n",
    "        yield features[j], labels[j]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-0.15791896 -1.368419  ]\n",
      " [-1.2912872  -2.9434786 ]\n",
      " [-1.7658867  -1.4701791 ]\n",
      " [ 0.17313462  0.61840177]\n",
      " [ 0.98486614  1.8532189 ]\n",
      " [ 0.98916334  1.760945  ]\n",
      " [-0.854792   -1.3276836 ]\n",
      " [ 0.8285209   1.9348817 ]\n",
      " [ 1.3753697   1.2648998 ]\n",
      " [-0.7374796  -0.71223205]] [ 8.530758   11.613669    5.662739    2.4489765  -0.1518561   0.18878557\n",
      "  6.994077   -0.7146609   2.6620245   5.160786  ]\n"
     ]
    }
   ],
   "source": [
    "batch_size = 10\n",
    "\n",
    "for X, y in data_iter(batch_size, features, labels):\n",
    "    print(X, y)\n",
    "    break"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.3 initialize weight"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "w = tf.Variable(tf.random.normal((num_inputs, 1), stddev=0.01))\n",
    "b = tf.Variable(tf.zeros((1,)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.4 define model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def linreg(X, w, b):\n",
    "    return tf.matmul(X, w) + b"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.5 define loss"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def squared_loss(y_hat, y):\n",
    "    return (y_hat - tf.reshape(y, y_hat.shape)) ** 2 /2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.6 define optimization"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def sgd(params, lr, batch_size):\n",
    "    for param in params:\n",
    "#         param[:] = param - lr * t.gradient(l, param) / batch_size\n",
    "        param.assign_sub(lr * t.gradient(l, param) / batch_size)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3.2.7 training"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch 1, loss 0.052947\n",
      "epoch 2, loss 0.000244\n",
      "epoch 3, loss 0.000044\n"
     ]
    }
   ],
   "source": [
    "lr = 0.03\n",
    "num_epochs = 3\n",
    "net = linreg\n",
    "loss = squared_loss\n",
    "\n",
    "for epoch in range(num_epochs):\n",
    "    for X, y in data_iter(batch_size, features, labels):\n",
    "        with tf.GradientTape(persistent=True) as t:\n",
    "            t.watch([w,b])\n",
    "            l = loss(net(X, w, b), y)\n",
    "        sgd([w, b], lr, batch_size)\n",
    "    train_l = loss(net(features, w, b), labels)\n",
    "    print('epoch %d, loss %f' % (epoch + 1, tf.reduce_mean(train_l)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "([2, -3.4], <tf.Variable 'Variable:0' shape=(2, 1) dtype=float32, numpy=\n",
       " array([[ 1.9989632],\n",
       "        [-3.3986626]], dtype=float32)>)"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "true_w, w"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(4.2,\n",
       " <tf.Variable 'Variable:0' shape=(1,) dtype=float32, numpy=array([4.199325], dtype=float32)>)"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "true_b, b"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "tf2.0",
   "language": "python",
   "name": "tf2.0"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
